import * as crypto from 'crypto';
import { LakalaConfig } from './config/lakala';
import { LAKALA_APP_ID, PRIVATE_KEY, SERIAL_NUMBER } from '../../../comm/constant';
import * as forge from 'node-forge';

/**
 * 拉卡拉工具类
 */
export class LakalaUtils {
  /**
   * 生成请求ID
   */
  generateRequestId(): string {
    const timestamp = Date.now().toString();
    const random = Math.random().toString(36).substring(2, 8);
    return `REQ${timestamp}${random}`.toUpperCase();
  }

  /**
   * 获取当前时间戳
   */
  getCurrentTimestamp(): string {
    return Math.floor(Date.now() / 1000).toString();
  }

  /**
   * 格式化时间
   */
  formatDateTime(date: Date = new Date()): string {
    return date.toISOString().replace(/T/, ' ').replace(/\..+/, '');
  }

  /**
   * 生成随机字符串
   */
  generateNonceStr(length: number = 32): string {
    const chars =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }

  /**
   * 生成商户号
   */
  generateMerchantNo(): string {
    const timestamp = Date.now().toString();
    const random = Math.random().toString().substring(2, 6);
    return `M${timestamp}${random}`;
  }

  /**
   * 生成合同号
   */
  generateContractNo(): string {
    const timestamp = Date.now().toString();
    const random = Math.random().toString().substring(2, 6);
    return `C${timestamp}${random}`;
  }

  /**
   * 金额格式化（元转分）
   */
  yuanToFen(yuan: number): number {
    return Math.round(yuan * 100);
  }

  /**
   * 金额格式化（分转元）
   */
  fenToYuan(fen: number): number {
    return Math.round(fen) / 100;
  }

  /**
   * 验证手机号
   */
  validatePhone(phone: string): boolean {
    const phoneRegex = /^1[3-9]\d{9}$/;
    return phoneRegex.test(phone);
  }

  /**
   * 验证邮箱
   */
  validateEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  /**
   * 验证身份证号
   */
  validateIdCard(idCard: string): boolean {
    const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    return idCardRegex.test(idCard);
  }

  /**
   * 验证营业执照号
   */
  validateBusinessLicense(license: string): boolean {
    // 统一社会信用代码18位
    const licenseRegex = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/;
    return licenseRegex.test(license);
  }

  /**
   * 验证银行卡号
   */
  validateBankCard(cardNo: string): boolean {
    const cardRegex = /^\d{16,19}$/;
    return cardRegex.test(cardNo);
  }

  /**
   * 构建签名字符串
   */
  buildSignString(params: Record<string, any>): string {
    // 过滤空值和签名字段
    const filteredParams = Object.keys(params)
      .filter(
        key =>
          params[key] !== null &&
          params[key] !== undefined &&
          params[key] !== '' &&
          key !== 'sign'
      )
      .sort()
      .reduce((obj, key) => {
        obj[key] = params[key];
        return obj;
      }, {} as Record<string, any>);

    // 构建签名字符串
    return Object.keys(filteredParams)
      .map(key => `${key}=${filteredParams[key]}`)
      .join('&');
  }

  /**
   * RSA签名
   */
  rsaSign(data: string, privateKey: string): string {
    try {
      const sign = crypto.createSign('RSA-SHA256');
      sign.update(data, 'utf8');
      return sign.sign(privateKey, 'base64');
    } catch (error) {
      throw new Error(`RSA签名失败: ${error.message}`);
    }
  }

  /**
   * RSA验签
   */
  rsaVerify(data: string, signature: string, publicKey: string): boolean {
    try {
      const verify = crypto.createVerify('RSA-SHA256');
      verify.update(data, 'utf8');
      return verify.verify(publicKey, signature, 'base64');
    } catch (error) {
      this.log('RSA验签失败', error);
      return false;
    }
  }

  /**
   * 构建请求头
   */
  buildHeaders(body: any, accessToken?: string): Record<string, string> {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      'User-Agent': 'Lakala-Merchant-SDK',
      'X-Request-Id': this.generateRequestId(),
      'X-Timestamp': this.getCurrentTimestamp(),
    };

    if (accessToken) {
      headers['Authorization'] = `Bearer ${accessToken}`;
    }

    return headers;
  }

  /**
   * 判断响应是否成功
   */
  isResponseSuccess(response: any): boolean {
    return response && response.code === LakalaConfig.RESPONSE_CODES.SUCCESS;
  }

  /**
   * 获取错误信息
   */
  getErrorMessage(response: any): string {
    if (!response) {
      return '响应数据为空';
    }

    return response.message || response.msg || '未知错误';
  }

  /**
   * 格式化商户类型
   */
  formatMerchantType(type: string): string {
    const typeMap = {
      [LakalaConfig.MERCHANT_TYPES.ENTERPRISE]: '企业商户',
      [LakalaConfig.MERCHANT_TYPES.INDIVIDUAL]: '小微商户',
    };

    return typeMap[type] || type;
  }

  /**
   * 格式化合同类型
   */
  formatContractType(type: string): string {
    const typeMap = {
      [LakalaConfig.CONTRACT_TYPES.SERVICE]: '服务合同',
      [LakalaConfig.CONTRACT_TYPES.PAYMENT]: '支付合同',
      [LakalaConfig.CONTRACT_TYPES.SETTLEMENT]: '结算合同',
    };

    return typeMap[type] || type;
  }

  /**
   * 格式化状态
   */
  formatStatus(
    status: string,
    type: 'merchant' | 'contract' | 'token'
  ): string {
    let statusMap: Record<string, string> = {};

    switch (type) {
      case 'merchant':
        statusMap = {
          [LakalaConfig.MERCHANT_STATUS.APPLYING]: '申请中',
          [LakalaConfig.MERCHANT_STATUS.SUBMITTED]: '已提交',
          [LakalaConfig.MERCHANT_STATUS.APPROVED]: '已通过',
          [LakalaConfig.MERCHANT_STATUS.REJECTED]: '已拒绝',
          [LakalaConfig.MERCHANT_STATUS.FAILED]: '失败',
        };
        break;
      case 'contract':
        statusMap = {
          [LakalaConfig.CONTRACT_STATUS.APPLYING]: '申请中',
          [LakalaConfig.CONTRACT_STATUS.PENDING_SIGN]: '待签署',
          [LakalaConfig.CONTRACT_STATUS.SIGNED]: '已签署',
          [LakalaConfig.CONTRACT_STATUS.REJECTED]: '已拒绝',
          [LakalaConfig.CONTRACT_STATUS.FAILED]: '失败',
        };
        break;
      case 'token':
        statusMap = {
          [LakalaConfig.TOKEN_STATUS.ACTIVE]: '有效',
          [LakalaConfig.TOKEN_STATUS.EXPIRED]: '已过期',
          [LakalaConfig.TOKEN_STATUS.REVOKED]: '已撤销',
        };
        break;
    }

    return statusMap[status] || status;
  }

  /**
   * 文件大小格式化
   */
  formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 B';

    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * 验证文件类型
   */
  validateFileType(fileName: string, allowedTypes: string[]): boolean {
    const ext = fileName.split('.').pop()?.toLowerCase();
    return ext ? allowedTypes.includes(ext) : false;
  }

  /**
   * 生成文件名
   */
  generateFileName(originalName: string, prefix: string = ''): string {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 8);
    const ext = originalName.split('.').pop();

    return `${prefix}${timestamp}_${random}.${ext}`;
  }

  /**
   * 数据脱敏
   */
  maskSensitiveData(
    data: string,
    type: 'phone' | 'idCard' | 'bankCard' | 'email'
  ): string {
    if (!data) return '';

    switch (type) {
      case 'phone':
        return data.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
      case 'idCard':
        return data.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
      case 'bankCard':
        return data.replace(/(\d{4})\d+(\d{4})/, '$1****$2');
      case 'email':
        return data.replace(/(.{2}).*(@.*)/, '$1****$2');
      default:
        return data;
    }
  }

  /**
   * 日志记录
   */
  log(message: string, data?: any): void {
    const timestamp = this.formatDateTime();
    console.log(`[${timestamp}] [Lakala] ${message}`, data || '');
  }

  /**
   * 错误日志记录
   */
  logError(message: string, error?: any): void {
    const timestamp = this.formatDateTime();
    console.error(`[${timestamp}] [Lakala Error] ${message}`, error || '');
  }

  /**
   * 延迟执行
   */
  async delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 重试执行
   */
  async retry<T>(
    fn: () => Promise<T>,
    maxAttempts: number = LakalaConfig.RETRY.MAX_ATTEMPTS,
    delay: number = LakalaConfig.RETRY.DELAY
  ): Promise<T> {
    let lastError: any;

    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        return await fn();
      } catch (error) {
        lastError = error;
        this.logError(`第${attempt}次尝试失败`, error);

        if (attempt < maxAttempts) {
          await this.delay(delay * attempt); // 递增延迟
        }
      }
    }

    throw lastError;
  }

  
  // 使用私钥生成签名
  generateSignature(message) {
    try {
      const pKey = forge.pki.privateKeyFromPem(PRIVATE_KEY);
      const md = forge.md.sha256.create();
      md.update(message, 'utf8');
      return forge.util.encode64(pKey.sign(md));
    } catch (e) {
      console.error('签名生成失败:', e);
      throw new Error('签名生成失败，请检查私钥格式');
    }
  }

  //构建拉卡拉请求头
  createAuthorization(body) {
    // 1. 动态生成参数
    const nonceStr = this.generateNonceStr(); // 12位随机字符串
    const timestamp = Math.floor(Date.now() / 1000); // 当前秒级时间戳

    // 2. 构建待签名字符串
    const bodyString = typeof body === 'string' ? body : JSON.stringify(body);
    const message = `${LAKALA_APP_ID}\n${SERIAL_NUMBER}\n${timestamp}\n${nonceStr}\n${bodyString}\n`;

    // 3. 生成签名
    const signature = this.generateSignature(message);

    return `LKLAPI-SHA256withRSA appid="${LAKALA_APP_ID}",serial_no="${SERIAL_NUMBER}",timestamp="${timestamp}",nonce_str="${nonceStr}",signature="${signature}"`;
  }
}
